//File	 : FCMeshConvertUtils.cpp
//Purpose: Implementation of the convert utils the graphics properties from 
//		   collada data format to mesh 3d-Coat graphics format and back.
//Data	 : 23/07/2009
//----------------------------------------------------------------------------
#include "stdafx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDMaterial.h"
#include "FCDocument/FCDEffect.h"
#include "FCDocument/FCDEffectProfile.h"
#include "FCDocument/FCDEffectStandard.h"
#include "FCDocument/FCDEffectParameter.h"
#include "FCDocument/FCDLibrary.h"
#include "FCDocument/FCDEffectTools.h"
#include "FCDocument/FCDGeometryMesh.h"
#include "FCDocument/FCDGeometrySource.h"
#include "FCDocument/FCDGeometryPolygons.h"
#include "FCDocument/FCDGeometryPolygonsTools.h"
#include "FCDocument/FCDGeometryPolygonsInput.h"
#include "FUtils/FUDaeEnum.h"
#include "FCMeshConvertUtils.h"


class hVec3:public comms::cVec3{//3 floats-s	
public:
	hVec3(){};
	hVec3(float a,float b,float c){
		x=a;
		y=b;
		z=c;
	}
	operator DWORD(){
		return *((DWORD*)&x)+*((DWORD*)&y)+*((DWORD*)&z);
	}	
	bool   operator == (const hVec3& c) const{
		return c.x==x && c.y==y && c.z==z;
	}
};

void FMVector4TwoColor(FMVector4 &fmVect, comms::cColor &cColor)
{
	cColor.a = fmVect.w;
	cColor.r = fmVect.x;
	cColor.g = fmVect.y;
	cColor.b = fmVect.z;
}

void ColorTwoFMVector4(comms::cColor &cColor, FMVector4 &fmVect )
{
	fmVect.w = cColor.a;
	fmVect.x = cColor.r;
	fmVect.y = cColor.g;
	fmVect.z = cColor.b;
}

namespace FCMeshConvertUtils {

void ConvertFCMaterial2CoatMaterial(FCDMaterial *material, 
									comms::cMeshConatainer &Mesh)
{
	if(!material) 
		return;
	FCDEffect* effect = material->GetEffect();
	FCDEffectProfile* profile = effect->GetProfile(0);
	FCDEffectStandard* effectStandard = (FCDEffectStandard*) profile;
	fstring mName = material->GetName();
	comms::cSurface m;
	m.Name = mName.c_str();
	FMVector4 ambient = effectStandard->GetAmbientColor();
	FMVector4TwoColor(effectStandard->GetAmbientColor(),m.Ambient);
	FMVector4TwoColor(effectStandard->GetSpecularColor(),m.Specular);
	FMVector4TwoColor(effectStandard->GetDiffuseColor(),m.Diffuse);
	FMVector4TwoColor(effectStandard->GetEmissionColor(),m.Gloss); //???
	m.Luminosity = effectStandard->GetEmissionFactor(); // ???
	m.Translucensy = effectStandard->GetTranslucencyFactor();
	m.Reflection = effectStandard->GetReflectivity();
	m.Refraction = effectStandard->GetIndexOfRefraction();
	m.Transparency = (effectStandard->GetTransparencyMode())?0.0:1.0;
	m.Shininess = effectStandard->GetShininess();
//  m.Color = ?
//	m.DepthModulator = ?;
	Mesh.GetMaterials().Add(m);
	Mesh.GetMaterials().GetLast().Name = material->GetName();
}
void ConvertFCMaterialLib2CoatMaterial(FCDMaterialLibrary *library, 
									   comms::cMeshConatainer &Mesh)
{
	FCDMaterial* fcMaterial = NULL;
	size_t entity_count = library->GetEntityCount();
	for(size_t i = 0; i < entity_count; i++ )
	{
		fcMaterial = library->GetEntity(i);
		ConvertFCMaterial2CoatMaterial(fcMaterial,Mesh);
	}
}
void ConvertFCTanBinorm2Coat( FCDGeometryMesh *fcMesh, 
							  comms::cMeshConatainer &Mesh)
{

	size_t polyCount = fcMesh->GetPolygonsCount();
	comms::cList<comms::cVec<comms::cVec3, 2> > &Tangents = Mesh.GetTangents(); 
	comms::cVec<comms::cVec3,2> R(comms::cVec3(-1,-1,-1),comms::cVec3(-1,-1,-1));
	for(size_t j = 0; j < polyCount;j++) 
	{
		FCDGeometryPolygons *polygons = fcMesh->GetPolygons(j);
		FCDGeometryPolygonsInput* pn = polygons->FindInput(FUDaeGeometryInput::Semantic::NORMAL);
		FCDGeometryPolygonsInput* ptn = polygons->FindInput(FUDaeGeometryInput::Semantic::TEXTANGENT);
		FCDGeometryPolygonsInput* pbn = polygons->FindInput(FUDaeGeometryInput::Semantic::TEXBINORMAL);
	
		if ( pn == NULL || ptn == NULL || pbn == NULL )
			continue;
		
		uint32* normalList = pn->GetIndices();
		uint32* tangList = (ptn)?ptn->GetIndices():0;
		uint32* binormList = (pbn)?pbn->GetIndices():0;
		
		size_t normalIndexCount = pn->GetIndexCount();
		size_t tanIndexCount = (ptn)?ptn->GetIndexCount():0;
		size_t binormIndexCount = (pbn)?pbn->GetIndexCount():0;
		
		FCDGeometrySource *tanSrc	 = ptn->GetSource();
		FCDGeometrySource *binormSrc = pbn->GetSource();

		const float* pBN = binormSrc->GetData();
		const float* pTN = tanSrc->GetData();
		int stride = binormSrc->GetStride();

		if(Tangents.IsEmpty()) {
			int count = pn->GetSource()->GetValueCount();
			Tangents.SetCapacity(count);
			Tangents.SetCount(count,R);
		}
		for(int i = 0; i < normalIndexCount;i++)
		{
			printf("in = %d itan = %d ibinorm = %d\n",
								normalList[i],
								tangList[i],
								binormList[i]);
			int index = normalList[i];
			comms::cVec3 bn,tn;
			bn = *(comms::cVec3*) (pBN + index * stride);
			tn = *(comms::cVec3*) (pTN + index * stride);
			if(Tangents[index]==R){
				Tangents[index].Set(tn,bn);
			}
		}
	}
}

void ConvertFCGSource2CoatSources(FCDGeometryMesh *fcMesh, 
								  comms::cMeshConatainer &Mesh)
{
	uni_hash<DWORD,hVec3,800000,8192> PosHash;
	comms::cList<DWORD> PosID;
	size_t meshSourceCount = fcMesh->GetSourceCount();
//	comms::cList<comms::cVec3> tangents;
//	comms::cList<comms::cVec3> binorms;
	for (size_t i = 0; i < meshSourceCount; ++i)
	{
		FCDGeometrySource* source = fcMesh->GetSource(i);
		uint32 stride = source->GetStride();
		size_t data_count = source->GetDataCount();
		size_t count  = source->GetValueCount();
		const float* ptr = source->GetData();
		switch(	source->GetType()){
				case FUDaeGeometryInput::POSITION:
					 if(stride >= 3){
						for (uint32 j = 0; j < count; ++j)
						{
							comms::cVec3 &vpos = *(comms::cVec3*)(ptr + j * stride);
							FMVector3 vect3 = *((FMVector3*)(ptr + j * stride));
							hVec3 v2(vpos.x,vpos.y,vpos.z);
							DWORD* id=PosHash.get(v2);
							if(id==NULL){				
							DWORD p=Mesh.GetPositions().Add(vpos);
							PosID.Add(p);
							PosHash.add(v2,p);								
							}
							else{
								PosID.Add(*id);
							}	
						}
					}
					break;
				case FUDaeGeometryInput::NORMAL:
					if (stride >=3){
						for (uint32 j = 0; j < count; ++j)
						{
							comms::cVec3 &Normal = *(comms::cVec3*) (ptr + j * stride);
							Mesh.GetNormals().Add(Normal);
						}
					}
					break;
				case FUDaeGeometryInput::TEXCOORD:
					if (stride >=2){
						for (uint32 j = 0; j < count; ++j)
						{
							comms::cVec2 &TexCoord = *(comms::cVec2*) (ptr + j * stride);
							Mesh.GetTexCoords().Add(TexCoord);
						}
					}
					break;
				case FUDaeGeometryInput::GEOBINORMAL:
					break;
				case FUDaeGeometryInput::GEOTANGENT:
					break;
				case FUDaeGeometryInput::UV:
					break;
				case FUDaeGeometryInput::TEXBINORMAL:
			/*		if (stride >=3){
						for (uint32 j = 0; j < count; ++j)
						{
							comms::cVec3 &binorm = *(comms::cVec3*) (ptr + j * stride);
							binorms.Add(binorm);
						}
					}
			*/	break;
				case FUDaeGeometryInput::TEXTANGENT:
			/*		if (stride >=3){
						for (uint32 j = 0; j < count; ++j)
						{
							comms::cVec3 &tangent = *(comms::cVec3*) (ptr + j * stride);
							tangents.Add(tangent);
						}
					}
			*/		break;
		}
	}	
/*	if(tangents.Count() || binorms.Count())
	{
		comms::cList<comms::cVec<comms::cVec3, 2> > &Tangents = Mesh.GetTangents(); 
		comms::cVec<comms::cVec3,2> CV;
		comms::cVec3 R(-1,-1,-1);
		int tanCount = tangents.Count();
		int binormCount = binorms.Count();
		int count = tanCount;
		if(count < binormCount)
			count = binormCount;
		for(size_t j = 0; j < count;j++){
			comms::cVec3 bn,tn;
			if(!binorms.IsEmpty()){
				bn = (j<binormCount)?binorms[j]:R;
			}
			if(!tangents.IsEmpty()){
				tn = (j<tanCount)?tangents[j]:R;
			}
			CV.Set(tn,bn);
			Tangents.Add(CV);
		}
	}
*/
}

//--------------------------------------------------------------
};